#include "Avalon/SignalHandling/TaskSignalHandler.hpp"
#include "Avalon/Base/Algorithm.hpp"
#include "Avalon/Threading/ThreadPool.hpp"

using namespace Avalon;
using namespace Avalon::SignalHandling;
using namespace Avalon::Threading;
using namespace boost;
using namespace std;

TaskSignalHandler::TaskSignalHandler()
    : m_signalProcessor(bind(&QueuedSignalHandler::HandleSignals,
        ref(m_queuedSignalHandler))) {
  m_queuedSignalHandler.SetQueuedSlot(bind(&TaskSignalHandler::OnSignalsQueued,
    this));
}

TaskSignalHandler::TaskSignalHandler(ThreadPool& threadPool)
    : m_threadPool(&threadPool),
      m_signalProcessor(bind(&QueuedSignalHandler::HandleSignals,
        ref(m_queuedSignalHandler))) {
  m_queuedSignalHandler.SetQueuedSlot(bind(&TaskSignalHandler::OnSignalsQueued,
    this));
}

TaskSignalHandler::~TaskSignalHandler() {
  unique_lock<mutex> lock(m_mutex);
  if(!m_results.empty()) {
    m_stopping = true;
    m_resultsEmptyCondition.wait(lock);
  }
}

void TaskSignalHandler::Initialize(ThreadPool& threadPool) {
  m_threadPool = &threadPool;
}

void TaskSignalHandler::OnSignalsQueued() {
  Async<void>* result = new Async<void>();
  Async<void>::State state;
  result->SetFinishedSlot(bind(&TaskSignalHandler::OnSignalsProcessed, this,
    result), Store(state));
  lock_guard<mutex> lock(m_mutex);
  m_threadPool->Queue(m_signalProcessor, Store(*result));
  m_results.push_back(result);
}

void TaskSignalHandler::OnSignalsProcessed(Async<void>* result) {
  lock_guard<mutex> lock(m_mutex);
  Remove(m_results, result);
  delete result;
  if(m_stopping && m_results.empty()) {
    m_resultsEmptyCondition.notify_one();
  }
}
